package com.zytool.easyrestful.core.utils;

import com.zytool.easyrestful.core.GenericEntity;
import lombok.extern.slf4j.Slf4j;

import javax.persistence.Table;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
public class EntityUtil {

    private static Map<Class<?>, Field[]> fieldCache = new HashMap<>();

    public static String getTableName(Class<?> clazz) {
        return getTable(clazz).name();
    }

    public static Table getTable(Class<?> clazz) {
        Table table = clazz.getAnnotation(Table.class);
        if (table != null) {
            return table;
        }
        throw new RuntimeException("Entity class Table annotation is null");
    }

    public static Field[] getEntityFields(Class<?> clazz) {
        Field[] cacheFields = fieldCache.get(clazz);
        if (cacheFields != null && cacheFields.length != 0) {
            return cacheFields;
        }
        List<Field> fieldList = getFields(clazz);
        Field[] validFields = new Field[fieldList.size()];
        fieldList.toArray(validFields);
        fieldCache.put(clazz, validFields);
        return validFields;
    }

    public static List<String> getFieldNames(Class<?> clazz) {
        return getFields(clazz).stream().map(Field::getName).collect(Collectors.toList());
    }

    public static List<Field> getFields(Class<?> clazz) {
        List<Field[]> allFields = new ArrayList<>();

        recursiveFields(clazz, allFields);

        Set<String> fieldNameSet = new HashSet<>();
        List<Field> fieldList = new ArrayList<>();
        Iterator iterator = allFields.iterator();
        while (true) {
            if (!iterator.hasNext()) {
                break;
            }
            Field[] fields = (Field[]) iterator.next();
            for (Field field : fields) {
                if (!fieldNameSet.contains(field.getName().toLowerCase())) {
                    fieldNameSet.add(field.getName().toLowerCase());
                    fieldList.add(field);
                } else {
                    log.warn("Entity属性已经存在, 不能重复加载父属性:class{}, field:{}", clazz.getName(), field.getName());
                }
            }
        }
        return fieldList;
    }

    public static void recursiveFields(Class<?> clazz, List<Field[]> allFields) {
        if (GenericEntity.class.isAssignableFrom(clazz)) {
            Field[] fields = clazz.getDeclaredFields();
            allFields.add(fields);
            Class<?> superClazz = clazz.getSuperclass();
            if (superClazz != null) {
                recursiveFields(superClazz, allFields);
            }
        }
    }
}
